package util

import (
	"bytes"
	"encoding/json"
	"io"
	"io/ioutil"
	"os"
	"pan/common/exception"
	"strings"
)

func PathJoin(path string, paths ...string) string {
	if path == "" {
		return path
	}
	if paths == nil || len(paths) == 0 {
		return path
	}
	var buff bytes.Buffer
	path = strings.TrimSpace(path)
	buff.WriteString(path)
	if !strings.HasSuffix(path, "/") {
		buff.WriteString("/")
	}
	for _, p := range paths {
		p = strings.TrimSpace(p)
		buff.WriteString(strings.TrimPrefix(p, "/"))
	}
	return buff.String()
}

func IsExists(filePath string) bool {
	if filePath == "" {
		return false
	}
	_, err := os.Stat(filePath)
	if err == nil {
		return true
	}
	if os.IsNotExist(err) {
		return false
	}
	return false
}

func CloseQuietly(closer io.Closer) {
	_ = closer.Close()
}

func LoadJsonFile(filePath string, data interface{}) error {
	if !IsExists(filePath) {
		return exception.NewExpectError("file not exists: %s", filePath)
	}
	file, err := os.Open(filePath)
	if err != nil {
		return err
	}
	defer CloseQuietly(file)
	bytes, err := ioutil.ReadAll(file)
	if err != nil {
		return err
	}
	if err = json.Unmarshal(bytes, data); err != nil {
		return err
	}
	return nil
}

func LoadTextFile(filePath string) (string, error) {
	if !IsExists(filePath) {
		return "", exception.NewExpectError("file not exists: %s", filePath)
	}
	bytes, err := ioutil.ReadFile(filePath)
	if err != nil {
		return "", err
	}
	return string(bytes), nil
}

func WriteStruct(filePath string, data interface{}) error {
	bytes, err := json.MarshalIndent(data, "", "\t")
	if err != nil {
		return err
	}
	return ioutil.WriteFile(filePath, bytes, os.FileMode(0666))
}

type CopyProgress func(num int64, written int64)

func Copy(dst io.Writer, src io.Reader, progress CopyProgress) (written int64, err error) {
	written = 0
	err = nil

	buf := make([]byte, 32*1024)
	for {
		readNum, e := src.Read(buf)
		if readNum > 0 {
			writeNum, e := dst.Write(buf[0:readNum])
			if writeNum < 0 || readNum < writeNum {
				readNum = 0
				if e == nil {
					e = exception.NewExpectError("invalid write result")
				}
			}
			written += int64(writeNum)
			if progress != nil {
				progress(int64(writeNum), written)
			}
			if e != nil {
				err = e
				return
			}
			if readNum != writeNum {
				err = exception.NewExpectError("short write")
				return
			}
		}
		if e != nil {
			if e == io.EOF {
				err = nil
				return
			}
			err = e
			return
		}
	}
}
